<template>
  <div
    v-if="!hidden"
    class="file_preview_module"
    @click="onDropClick"
    :style="{
      left: sidebar.opened ? '210px' : '54px'
    }"
  >
    <div
      :class="{
        'preview-container': true,
        isImageShow: ['jpg', 'png'].includes(currentExtName)
      }"
    >
      <template v-if="currentExtName === 'pdf'">
        <canvas v-for="page in pageSize" ref="pdfCanvas" :key="page" />
      </template>
      <div v-else-if="currentExtName === 'docx'" ref="viewer" class="docx" />
      <img v-else :src="currentImgDataUrl" />
      <div class="preview-tools"></div>
    </div>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import { Getter } from 'vuex-class'
import { Component, Prop, Watch, Ref, Emit } from 'vue-property-decorator'
// 三方库
import * as PDFJS from 'pdfjs-dist/legacy/build/pdf'
import { RenderParameters } from 'pdfjs-dist/types/src/display/api'
import { renderAsync } from 'docx-preview'
import { getExtend, readBuffer } from '@/utils/file'
import { Dictionary } from '@/interface/Basic'
PDFJS.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/legacy/build/pdf.worker.entry.js')
@Component
class WsFilePreview extends Vue {
  @Ref() canvas!: HTMLCanvasElement
  @Ref() viewer!: HTMLElement
  @Ref() pdfCanvas!: HTMLCanvasElement[]
  @Getter('sidebar') sidebar!: { opened: boolean }
  @Prop({ default: true }) hidden!: boolean
  @Prop({ required: true }) file!: File
  // 文件列表，缓存加载过的文件内容
  fileList: Dictionary<File> = {}
  currentFilename: string = ''
  currentImgDataUrl: string = ''
  // pdf
  currentPage: number = 1
  pageSize: number = 0
  // pdf
  get fileOptions() {
    return Object.keys(this.fileList).map(filename => {
      return { label: filename, value: filename }
    })
  }
  get currentExtName() {
    return getExtend(this.currentFilename)
  }
  @Watch('file')
  file_handler(newVal: File) {
    if (!newVal) return
    this.currentFilename = newVal.name
    this.$set(this.fileList, newVal.name, newVal)
  }
  @Watch('hidden')
  h_handler(newVal: boolean) {
    if (!newVal) {
      const ext = getExtend(this.currentFilename)
      this.previewFile(this.fileList[this.currentFilename], ext)
    }
  }
  async previewFile(file: File, ext: string) {
    this.$set(this.fileList, file.name, file)
    if (['jpg', 'png'].includes(ext)) {
      this.previewJPG(file)
    } else if (ext === 'pdf') {
      const buffer = await readBuffer(file)
      this.loadFile(buffer as ArrayBuffer)
    } else if (ext === 'docx') {
      const buffer = await readBuffer(file)
      this.previewDocx(buffer as ArrayBuffer, 'viewer')
    }
  }
  async previewJPG(file: File) {
    // if (this.fileList[buffer.name] !== null) return
    const fr = new FileReader()
    fr.readAsDataURL(file)
    fr.onload = e => {
      const result = e.target?.result
      if (!result || result === undefined) return
      this.currentImgDataUrl = result.toString()
    }
  }
  async loadFile(buffer: ArrayBuffer) {
    // 初始化pdf
    const pdfDoc = await PDFJS.getDocument(buffer).promise
    this.pageSize = pdfDoc.numPages
    this.$nextTick(() => this.previewPdf(buffer, 1))
  }
  previewPdf(buffer: ArrayBuffer, num = 1) {
    PDFJS.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/legacy/build/pdf.worker.entry.js')
    PDFJS.getDocument(buffer).promise.then(pdfDoc => {
      this.pageSize = pdfDoc.numPages
      pdfDoc.getPage(num).then(page => {
        const canvas = this.pdfCanvas[num - 1] as HTMLCanvasElement
        const ctx: any = canvas.getContext('2d')
        const dpr = window.devicePixelRatio || 1
        const bsr =
          ctx.webkitBackingStorePixelRatio ||
          ctx.mozBackingStorePixelRatio ||
          ctx.msBackingStorePixelRatio ||
          ctx.oBackingStorePixelRatio ||
          ctx.backingStorePixelRatio ||
          1
        const ratio = dpr / bsr
        const viewport = page.getViewport({ scale: 1.5 })
        canvas.width = viewport.width * ratio
        canvas.height = viewport.height * ratio
        canvas.style.width = viewport.width + 'px'
        canvas.style.height = viewport.height + 'px'
        ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
        if (!ctx) return
        const renderContext: RenderParameters = {
          canvasContext: ctx,
          viewport: viewport
        }
        // 数据渲染到canvas画布上
        page.render(renderContext)
        if (this.pageSize > this.currentPage) {
          setTimeout(() => {
            return this.previewPdf(buffer, num + 1)
          })
        }
      })
    })
  }
  previewDocx(buffer: ArrayBuffer, canvasName: 'viewer') {
    renderAsync(buffer, this[canvasName], undefined, {
      breakPages: true,
      ignoreLastRenderedPageBreak: true
    })
  }
  @Emit('close-preview')
  onDropClick(e: MouseEvent) {
    if ((e.target as HTMLElement).className === 'file_preview_module') {
      return true
    } else return false
  }
}
export default WsFilePreview
</script>

<style lang="less" scoped>
@import '~@/styles/variable.less';
.file_preview_module {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: @sidebarWidth;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1002;
  background-color: rgba(0, 0, 0, 0.2);
  .preview-container {
    position: relative;
    width: 80%;
    height: 80%;
    background-color: #ffffff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    overflow-y: auto;
    .preview-tools {
      position: absolute;
      top: 0;
      left: 0;
    }
  }
  .isImageShow {
    display: flex;
    align-items: center;
    justify-content: center;
    img {
      max-width: 100%;
    }
  }
}
</style>
